#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <time.h>

#define MAX 18192 /* in bytes, 8KB */
#define TCP_PORT   6749
#define RESPONSE_PORT   7549
#define CON_ACK 1000 //circa millisecondi di attesa con coda piena del 50%
#define CON_META 2000 //circa millisecondi di attesa con coda piena tra il 50% e il 75%
#define CON_3QUARTI 3000 //circa millisecondi di attesa con coda piena più del 75%

int msgCounter;
 
void *request_sensor_value();
void *obtain_responce();
void *thread_obtain_responce(void *arg);
void delay(int t); //aspetta un tempo uguale a 100000 cicli macchina per t
 
int main() {

	msgCounter = 0;

	//creazione threads
	pthread_t request_thread,responce_thread;
	pthread_create(&responce_thread,NULL,obtain_responce,NULL);
	sleep(10);
	pthread_create(&request_thread,NULL,request_sensor_value,NULL);
	pthread_exit(0);
}

/*
Thread che si occupa di mandare messaggi di richiesta alla soekris e aspetta di ricevere dalla soekris un messaggio con il quale gestire la velocità di trasmissione dati.
I messaggi mandati sono del tipo "idMsg,idSensore".
Attualmente, ma solo a scopo di prove, mando 8 messaggi in totale così suddivisi: 4 messaggi contenti idSesore 0 e 4 messaggi conteneti idSensore 1.
perchè? perchè la soekris conosce solo sensori con id 0 e 1! :D
NB: apro 1 solo socket per mandare tutti questi messaggi! :P

I messaggi che riceve possono essere di 3 tipi:
- ACK = vuol dire che la wifi può continuare a mandare messaggi senza problemi e senza rallentare (cioè alla velocità di default di 1 secondo).
- 1/2 = vuol dire che la coda della soekris è piena tra 1/2 e 3/4 --> con questo messaggio si chiede alla wifi di rallentare un pò --> nel mio caso ho impostato che se si riceve un pacchetto di questo tipo, la wifi manderà pacchetti ogni 2 secondi.
- 3/2 = vuol dire che la coda della soekris è piena tra 3/4 e (tot) --> con questo messaggio si chiede alal wifi di rallentare ancora di più rispetto al caso precedente --> nel mio caso ho impostato che se si riceve un messaggio di questo tipo, la wifi manda pacchetti ogni 3 secondi.
*/
void *request_sensor_value(){
	int sd; /* Il socket descriptor del client */
	struct sockaddr_in server_addr; /* l'indirizzo del server */
	int sleep_value = CON_ACK;
 
	/* Utilizzando la struttura hostent si definisce l'indirizzo del server */
	struct hostent *hp;
	hp = gethostbyname("0.0.0.0");
	//hp = gethostbyname("10.42.43.1");
 
	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(TCP_PORT);
	/* successivamente viene memorizzato nella struttura server_addr */
	server_addr.sin_addr.s_addr = ((struct in_addr*)(hp->h_addr)) -> s_addr;
 
 
	
	//Viene creato il socket descriptor
	if((sd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
		printf("Errore nella creazione della socket\n");
	
	printf("Numero Socket usato dalla wifi per MANDARE RICHIESTE alla soekris: %d\n",sd);

	// Viene connesso al server
	if(connect(sd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
		printf("Errore di connessione al server\n");
	
	//send(sd,"time",sizeof("time"),0);

	char anno[4];
	read(sd, anno, 4);
	char mese[4];
	read(sd, mese, 4);
	char giorno[4];
	read(sd, giorno, 4);
	char ora[4];
	read(sd, ora, 4);
	char minuti[4];
	read(sd, minuti, 4);
	char secondi[4];
	read(sd, secondi, 4);
	printf("\nTime_sokris:%s %s %s %s %s %s\n",anno, mese, giorno, ora, minuti, secondi);

	struct tm* master_time = malloc(sizeof(struct tm));
	master_time->tm_year= (atoi(anno)+1900);
	master_time->tm_mon= atoi(mese);
	master_time->tm_mday= atoi(giorno);
	master_time->tm_hour= atoi(ora);
	master_time->tm_min= atoi(minuti);
	master_time->tm_sec= atoi(secondi);

	struct tm* newtime;
	time_t t;	
	time(&t);
	newtime=localtime(&t);

	printf("\nTime_wifi:%d %d %d %d %d %d\n",(newtime->tm_year+1900),newtime->tm_mon,newtime->tm_mday,newtime->tm_hour,newtime->tm_min,newtime->tm_sec);

	signed int diff_anno=newtime->tm_year - master_time->tm_year + 1900;
	signed int diff_mese=newtime->tm_mon - master_time->tm_mon + 1;
	signed int diff_giorno=newtime->tm_mday - master_time->tm_mday;
	signed int diff_ora=newtime->tm_hour - master_time->tm_hour;
	signed int diff_minuti=newtime->tm_min - master_time->tm_min;
	signed int diff_secondi=newtime->tm_sec - master_time->tm_sec;

	printf("\nDIFFERENZA TIME:%d %d %d %d %d %d\n",diff_anno,diff_mese,diff_giorno,diff_ora,diff_minuti,diff_secondi);

	int numMessaggiDaInviare = 4;
	
	while(numMessaggiDaInviare!=0){
 	    //faccio così perchè per ora suppongo che esistono solo 2 sensori con ID:0 e ID:1
 		int i=0;
		for(i=0; i<2; i++){	  
	
			printf("\n\nSocket Number usato per inviare i dati: %d",sd);
			
			struct tm* newtime;
			time_t t;	
			time(&t);
			newtime=localtime(&t);

			int anno_pacch = newtime->tm_year - diff_anno;	
			int mese_pacch = newtime->tm_mon - diff_mese + 1;
			int giorno_pacch = newtime->tm_mday - diff_giorno;
			int ora_pacch = newtime->tm_hour - diff_ora;
			int minuti_pacch = newtime->tm_min - diff_minuti;
			int secondi_pacch = newtime->tm_sec - diff_secondi;

			int deadline=rand() % 10;

			char type[4] = "Aper";
			
			//invio il pacchetto:
			char packet[4]="Send";
			
			send(sd,packet,sizeof(packet),0); //mando "Send"
			sprintf(packet, "%d",msgCounter);		
			send(sd,packet,sizeof(packet),0); //mando "msgCounter"
			sprintf(packet, "%d",i);		
			send(sd,packet,sizeof(packet),0); //mando "idSensore" (cioè "i")
			sprintf(packet, "%d",anno_pacch);		
			send(sd,packet,sizeof(packet),0); //mando "anno_pacch"
			sprintf(packet, "%d",mese_pacch);		
			send(sd,packet,sizeof(packet),0); //mando "mese_pacch"
			sprintf(packet, "%d",giorno_pacch);		
			send(sd,packet,sizeof(packet),0); //mando "giorno_pacch"
			sprintf(packet, "%d",ora_pacch);		
			send(sd,packet,sizeof(packet),0); //mando "ora_pacch"
			sprintf(packet, "%d",minuti_pacch);		
			send(sd,packet,sizeof(packet),0); //mando "minuti_pacch"
			sprintf(packet, "%d",secondi_pacch);		
			send(sd,packet,sizeof(packet),0); //mando "secondi_pacch"
			sprintf(packet, "%d",deadline);		
			send(sd,packet,sizeof(packet),0); //mando "deadline"
			send(sd,type,3,0); //mando "type"
			

			printf("\nMessaggio inviato!");
			msgCounter++; //incremento il contatore degli ID di messaggi inviati
	
			//ricevo il messaggi di risposta per regolare la velocità di invio dei pacchetti
			char responce_to_set_sleep[MAX];
			read(sd, responce_to_set_sleep, MAX);
			printf("\nRisposta dal server per regolare lo sleep: %s\n\n",responce_to_set_sleep);
	
			if(responce_to_set_sleep == "ACK"){
				sleep_value = CON_ACK; //1 secondo
			}else if(responce_to_set_sleep == "1/2"){
				sleep_value = CON_META; // 2 secondi
			}else if(responce_to_set_sleep == "3/4"){
				sleep_value = CON_3QUARTI; // 3 secondi
			}
	
			delay(sleep_value);
		
		}
		numMessaggiDaInviare--;
	}//fine while


	char end[4] = "END/";
	
	//per interrompere la comunicazione, mando il messaggio "END/"
	send(sd,end,sizeof(end),0);
	
	printf("\n*** Mando END per chiudere il socket di invio dati ***\n");
 
	close(sd);

	pthread_exit(0);
}


/*
Thread che sta in ascolto sulla porta "RESPONSE_PORT" e che si limita a sganciare un worker thread in caso di "accept" della connessione.
*/
void *obtain_responce(){
	int sockfd, newsockfd, clilen;
	struct sockaddr_in cli_addr, serv_addr;
	pthread_t thread_listener_request;
	
	printf("Creazione Listener di RESPONCE\n");

	if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
		printf("server: can't open stream socket\n");

	memset((char *) &serv_addr, 0, sizeof(serv_addr));
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	serv_addr.sin_port = htons(RESPONSE_PORT);
	
	if(bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
		printf("server: can't bind local address\n");	
	
	listen(sockfd, 200);
	
	printf("Listener di RESPONCE Creato e Socket creata\n");
	printf("Socket NUMBER del thread della wifi che si mette in ascolto delle risposte: %d",sockfd);

	for(;;){
		clilen = sizeof(cli_addr);
		newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);

		if(newsockfd < 0)
			printf("Listener di RESPONCE: accept error\n");

		/* create a new thread to process the incomming request */
		pthread_create(&thread_listener_request,NULL,thread_obtain_responce,(void *) newsockfd);

		/* the server is now free to accept another socket request */
	}
}

/*
Worker Thread. Ha il compito di ricevere i messaggi di risposta contenenti i valori dei sensori e inviati dalla soekris.
Come sapete, purtroppo, ad ogni risposta verrà sganciato uno di questi thread. Il motivo di questa mi scelta lo sapete già (ossia evitare che la wifi lavori alla stessa velocità del bluetooth).
I messaggi che riceve sono:
- numMsg
- idSensore
- sensorValue
*/
void *thread_obtain_responce(void *arg){
	int mysocfd = (int) arg;
	
	char numMsg[4];
	read(mysocfd, numMsg, 4);
	char idSensore[4];
	read(mysocfd, idSensore, 4);
	char dataValueSensore[4];
	read(mysocfd, dataValueSensore, 4);
	
	//printf("\n1: %s - 2: %s - 3: %s\n",numMsg,idSensore,dataValueSensore);
	
	int a = atoi(numMsg);
	int b = atoi(idSensore);
	int c = atoi(dataValueSensore);
	
	printf("\n --> Ho ricevuto: [%d,%d,%d] <--\n",a,b,c);
	
	//close(mysocfd);
	//pthread_exit((void *)0);
}//fine request_handling

/*
Poichè la funzione sleep accetta solo numeri interi per attendere Secondi e la funzione "usleep" non mi funzionava... mi sono inventata questa funzione
che consete di aspettare anche millisecondi!
*/
void delay(int t){
int i;
while(t>0){
	    for (i=0;i<100000;i++);
	    	t--;
	    }
}
